
//=============================================================
void WattsStrogatz (std::vector<std::vector<int>> &Graph
                    , int population
                    , int num_neighbors
                    , int range
                    , float graph_irregular
                    ) {

   // 99% of the random numbers will be within the variation prescribed by the user.
   std::normal_distribution<double>  rnd_neighbors (num_neighbors, range / 3.0);

   Graph.clear();

   Graph.resize (population);

   std::vector<int> neighbors_of_A;

   int nodeA, nodeB, nodeBirr;

   // For each Person
   for (nodeA = 0; nodeA < population; nodeA++) {

      // Prepare array of neighbors of this Person.
      neighbors_of_A.clear();

      // Quantity of Neighbors that we'll create.
      int q = rnd_neighbors(Generator);

      int radius = q / 2; if  (radius < 1) radius = 1;

      // How many people are outside the Regular Neighborhood?
      int n4irregular = population - 1 - q;  // answer: everyone except me and neighbors

      for (int j = 0; j <= radius; j++) {

         int nodeB = ((nodeA + j) + population) % population;

         if (nodeA == nodeB) continue;
 
         // Random chance of breaking regularity.
         if (Probability(graph_irregular)) {

            // Try 5 times creating random neighbor.
            // If   (Population - num_neighbors)  is small, it can be hard
            //    or even impossible to create those links.
            for (int k = 0; k < 5; k++) {
               
               int t  = n4irregular * RndUniform(Generator);

               // Here's candidate neighbor to Person[i].
               nodeBirr = (nodeA + 1 +  q + t) % population; 

               // Should NEVER happen, but let's be 100% sure.
               if (nodeBirr == nodeA) break;
               
               // Don't repeat neighbors. 
               if (neighbors_of_A.end() == 
                  find (neighbors_of_A.begin(), neighbors_of_A.end(), nodeBirr)) {
                  nodeB = nodeBirr;
                  break;
               }
            }
         }

         // Add neighbor to the list of Person[i]
         neighbors_of_A.push_back(nodeB);

         // Ensure symmetry (A is neighbor of B who is neighbor of A).
         if (Graph[nodeB].end() == 
            find (Graph[nodeB].begin(), Graph[nodeB].end(), nodeA)) {
            Graph[nodeB].push_back (nodeA);
         }
      }

      // Add list of neighbors to the graph.
      Graph[nodeA] = neighbors_of_A;
   }
}




//==========================================================================================
//
// Create output for GraphWiz, so that we get a picture of the graph
//
//==========================================================================================
void CreateDotFile (std::string filepath) {

   std::ofstream arq;

   arq.open(filepath,std::ofstream::out|std::ofstream::trunc);  // zero file content, not append

   arq << "strict graph InfectionSimulation { \n";

   arq << "layout=circo; \n node[shape=point]; \n";


   int k = 0;

   for (auto a: Graph) {

      for (auto b: a)
         arq << k << " -- " << b << ";\n";

      ++k;
   }

   arq << "}\n";

   arq.close ();
}






//==========================================================================================
//
// Save Graph Structure
//
// From marcinj @ StackOverflow
//==========================================================================================

bool SaveGraph(std::string path, const std::vector<std::vector<int> >& myVector) {

    std::ofstream FILE(path, std::ios::out | std::ofstream::binary);

    if (FILE.fail())
       return false;

    // Store size of the outer vector
    int s1 = myVector.size();

    FILE.write (reinterpret_cast<const char *>(&s1), sizeof(s1));

    // Now write each vector one by one
    for (auto& v : myVector) {         

        // Store its size
        int size = v.size();

        FILE.write (reinterpret_cast<const char *>(&size), sizeof(size));

        // Store its contents
        FILE.write (reinterpret_cast<const char *>(&v[0]), v.size() * sizeof(int));
    }

    FILE.close();   

    return true;
}

//==========================================================================================
//
// Load Graph Structure
//
// From marcinj @ StackOverflow
//==========================================================================================

bool LoadGraph(std::string path,  std::vector<std::vector<int> >& myVector) {

    std::ifstream FILE (path, std::ios::in | std::ifstream::binary);

    int size = 0;

    FILE.read (reinterpret_cast<char *>(&size), sizeof(size));

    if (FILE.fail())
       return false;

    myVector.resize(size);

    for (int n = 0; n < size; ++n) {

        int size2 = 0;

        FILE.read(reinterpret_cast<char *>(&size2), sizeof(size2));

        int f;        

        for ( int k = 0; k < size2; ++k ) {
            FILE.read(reinterpret_cast<char *>(&f), sizeof(f));
            myVector[n].push_back(f);   
        }
    }

   return true;
}
